#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Build-in / Std

'''
Created on 2016年9月1日

@author: Hawk
'''
import sys
import wx
import wx.grid
import MDIChildFrameBase
import BaseDialog
from model.Model import *
from action.Action import *
from misc.Excel import *
from ControlID import ControlID
import datetime
import calendar

class SummaryByProjectFrame(MDIChildFrameBase.MDIChildFrameBase):
    menu_title_in_menubar = "&Summary"

    def __init__(self, *args, **kwargs):
        MDIChildFrameBase.MDIChildFrameBase.__init__(self, *args, **kwargs)
        self.InitMenu()

        self.panel = wx.Panel(self)
        self.summary_grid = wx.grid.Grid(
            self.panel,
            - 1,
            style=wx.LC_REPORT)

        self.summary_grid.CreateGrid(1, 1)

        #wx.EVT_LIST_ITEM_RIGHT_CLICK(
        #    self.ListCtrl_ProjectList,
        #    - 1,
        #    self.OnProjectListRightClick)

        self.last_hover_pos = (0, 0)

        self.merged_cells = []

        self.InitData()

        self.sizer_left = wx.BoxSizer(wx.HORIZONTAL)
        self.sizer_left.Add(self.summary_grid, 1, wx.EXPAND | wx.ALL)
        self.panel.SetSizer(self.sizer_left)
        self.sizer_left.Fit(self)

    def ResizeGrid(self, new_row_count, new_col_count):
        self.summary_grid.DeleteRows(0, self.summary_grid.GetNumberRows())
        self.summary_grid.DeleteCols(0, self.summary_grid.GetNumberCols())

        self.summary_grid.AppendRows(new_row_count)
        self.summary_grid.AppendCols(new_col_count)

    def InitData(self):
        #if hasattr(self, 'summary_grid') and self.summary_grid is not None:
        #    self.summary_grid.Destroy()
        self.project_list = Project.select().where(Project.deleted == False)
        self.sku_list = Sku.select().where(Sku.deleted == False)

        self.table_header_fixed_row_count = 2
        self.table_header_first_row_idx = 0
        self.table_header_second_row_idx = 1

        # Fill header
        self.summary_by_project_header_1 = [u'Summary by Project']
        self.summary_by_project_header_2 = [u'Phase', u'Development', u'Maintainence', u'Total']

        self.summary_by_sku_header_1 = [u'Summary by Sku']
        self.summary_by_sku_header_2 = [u'Phase', u'Development', u'Maintainence', u'Total']

        max_count = len(self.project_list) if len(self.project_list) > len(self.sku_list) else len(self.sku_list)
        self.row_count = max_count + self.table_header_fixed_row_count
        self.col_count = len(self.summary_by_project_header_2) + 2 + len(self.summary_by_sku_header_2)
        self.start_idx_of_summary_by_sku = len(self.summary_by_project_header_2) + 2

        self.ResizeGrid(self.row_count, self.col_count)

        for col_idx, text in enumerate(self.summary_by_project_header_1):
            self.summary_grid.SetCellSize(self.table_header_first_row_idx, col_idx, 1, len(self.summary_by_project_header_2));
            self.summary_grid.SetCellAlignment(self.table_header_first_row_idx, col_idx, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE);
            self.summary_grid.SetCellValue(self.table_header_first_row_idx, col_idx, text)

        for idx, text in enumerate(self.summary_by_project_header_2):
            col_idx = idx
            self.summary_grid.SetCellSize(self.table_header_second_row_idx, col_idx, 1, 1);
            self.summary_grid.SetCellAlignment(self.table_header_second_row_idx, col_idx, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE);
            self.summary_grid.SetCellValue(self.table_header_second_row_idx, col_idx, text)

        for col_idx, text in enumerate(self.summary_by_sku_header_1):
            col_idx = col_idx + self.start_idx_of_summary_by_sku
            self.summary_grid.SetCellSize(self.table_header_first_row_idx, col_idx, 1, len(self.summary_by_sku_header_2));
            self.summary_grid.SetCellAlignment(self.table_header_first_row_idx, col_idx, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE);
            self.summary_grid.SetCellValue(self.table_header_first_row_idx, col_idx, text)

        for idx, text in enumerate(self.summary_by_sku_header_2):
            col_idx = idx + self.start_idx_of_summary_by_sku
            self.summary_grid.SetCellSize(self.table_header_second_row_idx, col_idx, 1, 1);
            self.summary_grid.SetCellAlignment(self.table_header_second_row_idx, col_idx, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE);
            self.summary_grid.SetCellValue(self.table_header_second_row_idx, col_idx, text)

        # Fill data
        def get_project_mm(project):
            develop_mm = 0
            maintain_mm = 0
            for product in Product.select().where((Product.project == project) & (Product.deleted == False)):
                for record in Record.select().where((Record.product == product) & (Record.deleted == False)):
                    develop_mm += record.development_mm;
                    maintain_mm += record.maintenance_mm;

            return (develop_mm, maintain_mm)

        for idx, project in enumerate(self.project_list):
            row_idx = idx + self.table_header_fixed_row_count
            develop_mm, maintain_mm = get_project_mm(project)

            self.summary_grid.SetCellValue(row_idx, 0, project.name)
            self.summary_grid.SetCellValue(row_idx, 1, str(develop_mm))
            self.summary_grid.SetCellValue(row_idx, 2, str(maintain_mm))
            self.summary_grid.SetCellValue(row_idx, 3, str(develop_mm + maintain_mm))

        def get_sku_mm(sku):
            develop_mm = 0
            maintain_mm = 0
            for product in Product.select().where((Product.sku == sku) & (Product.deleted == False)):
                for record in Record.select().where((Record.product == product) & (Record.deleted == False)):
                    develop_mm += record.development_mm;
                    maintain_mm += record.maintenance_mm;

            return (develop_mm, maintain_mm)

        for idx, sku in enumerate(self.sku_list):
            row_idx = idx + self.table_header_fixed_row_count
            develop_mm, maintain_mm = get_sku_mm(sku)

            self.summary_grid.SetCellValue(row_idx, self.start_idx_of_summary_by_sku + 0, sku.name)
            self.summary_grid.SetCellValue(row_idx, self.start_idx_of_summary_by_sku + 1, str(develop_mm))
            self.summary_grid.SetCellValue(row_idx, self.start_idx_of_summary_by_sku + 2, str(maintain_mm))
            self.summary_grid.SetCellValue(row_idx, self.start_idx_of_summary_by_sku + 3, str(develop_mm + maintain_mm))

            #self.summary_grid.GetGridWindow().Bind(wx.EVT_MOTION, self.onMouseOver)
        f = self.summary_grid.GetFont()
        dc = wx.WindowDC(self.summary_grid)
        dc.SetFont(f)
        self.col_size_list = [i - i for i in range(self.col_count)]
        for row_idx in range(1, self.row_count):
            for col_idx in range(self.col_count):
                value = str(self.summary_grid.GetCellValue(row_idx, col_idx)).strip()
                width, height = dc.GetTextExtent(value)
                self.col_size_list[col_idx] = width if width > self.col_size_list[col_idx] else self.col_size_list[col_idx]
        for col_idx in range(self.col_count):
            if self.col_size_list[col_idx] != 0:
                self.summary_grid.SetColSize(col_idx, int(self.col_size_list[col_idx] * 1.5))

    def onMouseOver(self, event):
        """
        Displays a tooltip over any cell in a certain column
        """
        # Use CalcUnscrolledPosition() to get the mouse position within the 
        # entire grid including what's offscreen
        # This method was suggested by none other than Robin Dunn
        x, y = self.summary_grid.CalcUnscrolledPosition(event.GetX(), event.GetY())
        coords = self.summary_grid.XYToCell(x, y)
        col = coords[1]
        row = coords[0]

        if self.last_hover_pos == (row, col):
            return

        self.last_hover_pos = (row, col)
        records = self.getRecordsAt(row, col)
        #print '(%d, %d)' % (row, col), "record count:%d" % len(records)

        if len(records) > 0:
            msg = ''
            for r in records:
                if r.is_mp:
                    msg += "{date} {version} {wwversion} {mm} *\n".format(date=r.date, version=r.version, wwversion=r.ww_version, mm=r.development_mm)
                else:
                    msg += "{date} {version} {wwversion} {mm}\n".format(date=r.date, version=r.version, wwversion=r.ww_version, mm=r.maintenance_mm)
            event.GetEventObject().SetToolTipString(msg)
        else:
            event.GetEventObject().UnsetToolTip()

    def getRecordsAt(self, row_idx, col_idx):
        product_idx = row_idx - self.table_header_fixed_row_count
        month_idx = col_idx - len(self.table_headers)

        if product_idx >= 0 and product_idx < len(self.product_list) and month_idx > 0 and month_idx < len(self.year_labels) * 12:
            year_idx = month_idx / 12
            month_idx = month_idx % 12

            product = self.product_list[product_idx]

            year = self.year_labels[year_idx]
            month = self.month_labels[month_idx]

            start_date_value = datetime.date(int(year), int(month), 1) #int("%d%02d%02d" % (int(year), int(month), 0))
            end_date_value = datetime.date(int(year), int(month), calendar.monthrange(int(year), int(month))[1]) #int("%d%02d%02d" % (int(year), int(month), 32))

            return Record.select().where((Record.product == product.id) & (Record.date >= start_date_value) & (Record.date <= end_date_value))

        return []

    def getColumIndexByDate(self, release_date):
        fixed_col_count = len(self.table_headers)
        index_of_year = self.year_labels.index(str(release_date.year))

        index_of_month = self.month_labels.index(str(release_date.month))
        col_idx = fixed_col_count + index_of_year * 12 + index_of_month

        return col_idx

    def InitMenu(self):
        self.menuBar_menubar_menu_items = [
            {'id': ControlID.MENUBAR_MENU_ITEM_SKU_ADD, 'title': u'Add', 'separator': False, 'IsShown': lambda : False},
            {'id': ControlID.MENUBAR_MENU_ITEM_SKU_REFRESH, 'title': u'Refresh', 'separator': False, 'IsShown': lambda : True,
                'hasSub': False,
                'sub' : [{'id': ControlID.MENUBAR_MENU_ITEM_CATEGORY_ADD, 'title': u"导出为CHM(UTF-8)"}]},
            {'id': ControlID.MENUBAR_MENU_ITEM_EXPORT_XLS, 'title': u'Export', 'separator': False, 'IsShown': lambda : True},
            ]
        self.menu = self.BuildMenuItems(self.menuBar_menubar_menu_items, self.OnMenubarMenu_Select)

    def OnMenubarMenu_Select(self, event, menu_item, path):
        id = event.GetId()
        if id == ControlID.MENUBAR_MENU_ITEM_SKU_ADD:
            pass
        elif id == ControlID.MENUBAR_MENU_ITEM_SKU_REFRESH:
            self.InitData()
        elif id == ControlID.MENUBAR_MENU_ITEM_EXPORT_XLS:
            self.ExportXLSX()

    def _gen_cell_range(self, start_row_idx, start_col_idx, end_row_idx, end_col_idx):
        cells = []
        for row in range(start_row_idx, end_row_idx):
            for col in range(start_col_idx, end_col_idx):
                cells.append((row, col))

        return cells

    def AddMergedCells(self, start_row_idx, start_col_idx, end_row_idx, end_col_idx):
        if not hasattr(self, 'merged_cells') or self.merged_cells is None:
            self.merged_cells = []
        self.merged_cells.extend(self._gen_cell_range(start_row_idx, start_col_idx, end_row_idx, end_col_idx))

    def ExportXLSX(self):
        row_count = self.summary_grid.GetNumberRows()
        col_count = self.summary_grid.GetNumberCols()

        data_range_cells = self._gen_cell_range(
                                                2,
                                                1,
                                                2 + len(self.project_list),
                                                len(self.summary_by_project_header_2))
        data_range_cells_2 = self._gen_cell_range(
                                                2,
                                                self.start_idx_of_summary_by_sku + 1,
                                                2 + len(self.sku_list),
                                                self.start_idx_of_summary_by_sku + 1 + len(self.summary_by_sku_header_2))
        data_range_cells.extend(data_range_cells_2)

        import xlsxwriter
        import misc.XLSX as xlsx

        saved_file_path = ""

        dialog = wx.FileDialog(None, xlsx.excel_file_chose_caption, os.getcwd(),
                xlsx.gen_export_xlsx_file_name("SummaryByProject"), xlsx.excel_file_chose_wildcard, wx.SAVE)
        if dialog.ShowModal() == wx.ID_OK:
            saved_file_path = dialog.GetPath()
        else:
            return

        if not saved_file_path.endswith(".xlsx"):
            self.showMessageBox(u"导出失败! 文件扩展名必须是xlsx!")
            return

        workbook = xlsxwriter.Workbook(saved_file_path, {'default_date_format': 'dd/mm/yy'})
        worksheet = workbook.add_worksheet()

        self.merged_cells = []
        for row_idx in range(row_count):
            for col_idx in range(col_count):
                row_h, col_w = self.summary_grid.GetCellSize(row_idx, col_idx)
                value = self.summary_grid.GetCellValue(row_idx, col_idx).strip()

                if cmp(value, '') != 0:
                    if (row_idx, col_idx) not in self.merged_cells:
                        worksheet.set_row(row_idx, 15)
                        worksheet.set_column(col_idx, col_idx, 15)
                        if (row_idx, col_idx) in data_range_cells:
                            xlsx.write_cell(workbook, worksheet, row_idx, col_idx, float(value), row_height=row_h, col_width=col_w)
                        elif row_idx < self.table_header_fixed_row_count:
                            xlsx.write_cell(workbook, worksheet, row_idx, col_idx, value, row_height=row_h, col_width=col_w, format=xlsx.header_format)
                        else:
                            xlsx.write_cell(workbook, worksheet, row_idx, col_idx, value, row_height=row_h, col_width=col_w, format=xlsx.default_align_left_format)
                        if row_h > 1 or col_w > 1:
                            self.AddMergedCells(row_idx, col_idx, row_idx + row_h, col_idx + col_w)
        workbook.close()
        self.showMessageBox(u"导出成功!")

    def GetCellType(self, row_idx, col_idx):
        # Cell type
        # 0. EMPTY
        # 1. FILL GREEN, Sync WW
        # 2. FILL YELLOW, No Sync
        # 3. FILL RED, MP
        # 4. FILL GRAY, Phase out
        # [(r, g, b, a)]
        colors = [(255, 255, 255, 255), (0, 255, 0, 255), (255, 255, 0, 255), (255, 0, 0)]
        bkg = self.summary_grid.GetCellBackgroundColour(row_idx, col_idx)
        if bkg in colors:
            return colors.index(bkg)
        return 0

    def OnProjectListRightClick(self, event):
        self.selected_row_index = event.GetText()

        self.sku_menu_itemms = [
            {'id': ControlID.SKU_LIST_MENU_VIEW, 'title': u"查看"},
            {'id': ControlID.SKU_LIST_MENU_DELETE, 'title': u"删除"}
            ]

        menu = self.BuildMenuItems(self.sku_menu_itemms, self.OnMenuSelect_SkuList)
        self.PopupMenu(menu, event.GetPoint())
        menu.Destroy()

    def OnMenuSelect_SkuList(self, event, menu_item, path):
        id = event.GetId()
        if id == ControlID.SKU_LIST_MENU_DELETE:
            self.selected_row_index = int(self.selected_row_index) - 1
            msg = Action().ProjectMgr.del_project(self.project_list[self.selected_row_index].id)
            if msg:
                self.InitData()
            else:
                self.showMessageBox(msg.message)

    def OnActive(self):
        #print '%s has been actived' % self.GetTitle()
        parent_menubar = self.GetParent().GetMenuBar()
        pos = parent_menubar.FindMenu(self.menu_title_in_menubar)
        if pos == -1:
            parent_menubar.Insert(1, self.menu, self.menu_title_in_menubar)

    def OnDeactive(self):
        #print '%s has been deactived' % self.GetTitle()
        parent_menubar = self.GetParent().GetMenuBar()
        pos = parent_menubar.FindMenu(self.menu_title_in_menubar)
        if pos != -1:
            parent_menubar.Remove(pos)

